import os
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import threading
import time

class FileTreeAnalyzer(tk.Tk):
    def __init__(self):
        super().__init__()
        
        self.title("文件树分析器")
        self.geometry("800x600")
        
        # 创建主框架
        self.main_frame = ttk.Frame(self)
        self.main_frame.pack(expand=True, fill='both', padx=10, pady=10)
        
        # 创建控制区域
        self.create_control_area()
        
        # 创建状态显示区域
        self.create_status_area()
        
        # 创建预览区域
        self.create_preview_area()
        
        # 初始化变量
        self.is_processing = False
        self.current_folder = ""
        
    def create_control_area(self):
        # 文件夹选择
        folder_frame = ttk.Frame(self.main_frame)
        folder_frame.pack(fill='x', pady=5)
        
        ttk.Label(folder_frame, text="目标文件夹:").pack(side='left')
        self.folder_path = tk.StringVar()
        ttk.Entry(folder_frame, textvariable=self.folder_path).pack(side='left', expand=True, fill='x', padx=5)
        ttk.Button(folder_frame, text="浏览", command=self.select_folder).pack(side='left')
        
        # 排除设置区域
        exclude_label_frame = ttk.LabelFrame(self.main_frame, text="排除设置")
        exclude_label_frame.pack(fill='x', pady=5)
        
        # 排除文件后缀设置
        exclude_ext_frame = ttk.Frame(exclude_label_frame)
        exclude_ext_frame.pack(fill='x', pady=5, padx=5)
        
        ttk.Label(exclude_ext_frame, text="排除文件后缀:").pack(side='left')
        # 在这里自定义要排除的文件后缀
        self.exclude_ext = tk.StringVar(value=".git,.pyc,.exe,.dll,.pyd,.so,.dylib,.cache,.png,.doc,.docx,.pdf,.bat,.sh,.txt,.gitignore,.json,.md,.jpg")
        ttk.Entry(exclude_ext_frame, textvariable=self.exclude_ext).pack(side='left', expand=True, fill='x', padx=5)
        
        # 排除文件夹设置
        exclude_dir_frame = ttk.Frame(exclude_label_frame)
        exclude_dir_frame.pack(fill='x', pady=5, padx=5)
        
        ttk.Label(exclude_dir_frame, text="排除文件夹:").pack(side='left')
        # 在这里自定义要排除的文件夹
        self.exclude_dirs = tk.StringVar(value="temp,tmp,.git,.idea,__pycache__,venv,.venv,node_modules,build,dist,.vscode,migrations,tests,logs,instance")
        ttk.Entry(exclude_dir_frame, textvariable=self.exclude_dirs).pack(side='left', expand=True, fill='x', padx=5)
        
        # 操作按钮
        button_frame = ttk.Frame(self.main_frame)
        button_frame.pack(fill='x', pady=5)
        
        self.analyze_button = ttk.Button(button_frame, text="开始分析", command=self.start_analysis)
        self.analyze_button.pack(side='left', padx=5)
        
        self.save_button = ttk.Button(button_frame, text="保存Markdown", command=self.save_markdown, state='disabled')
        self.save_button.pack(side='left', padx=5)
        
    def create_status_area(self):
        status_frame = ttk.LabelFrame(self.main_frame, text="状态")
        status_frame.pack(fill='x', pady=5)
        
        self.progress = ttk.Progressbar(status_frame, mode='determinate')
        self.progress.pack(fill='x', padx=5, pady=5)
        
        self.status_label = ttk.Label(status_frame, text="就绪")
        self.status_label.pack(pady=5)
        
    def create_preview_area(self):
        preview_frame = ttk.LabelFrame(self.main_frame, text="预览")
        preview_frame.pack(expand=True, fill='both', pady=5)
        
        self.preview_text = tk.Text(preview_frame, wrap='word')
        self.preview_text.pack(expand=True, fill='both', padx=5, pady=5)
        
        scrollbar = ttk.Scrollbar(preview_frame, command=self.preview_text.yview)
        scrollbar.pack(side='right', fill='y')
        self.preview_text.configure(yscrollcommand=scrollbar.set)
        
    def select_folder(self):
        folder = filedialog.askdirectory()
        if folder:
            self.folder_path.set(folder)
            
    def start_analysis(self):
        if not self.folder_path.get():
            messagebox.showerror("错误", "请选择目标文件夹")
            return
            
        if self.is_processing:
            return
            
        self.is_processing = True
        self.analyze_button.config(state='disabled')
        self.save_button.config(state='disabled')
        self.preview_text.delete(1.0, tk.END)
        self.progress['value'] = 0
        
        threading.Thread(target=self.analyze_folder, daemon=True).start()
        
    def analyze_folder(self):
        try:
            self.markdown_content = "# 文件树分析报告\n\n"
            self.markdown_content += f"## 目标文件夹: {self.folder_path.get()}\n\n"
            
            # 解析排除设置
            exclude_extensions = set(ext.strip() for ext in self.exclude_ext.get().split(','))
            exclude_directories = set(dir.strip() for dir in self.exclude_dirs.get().split(','))
            
            # 获取文件总数用于进度计算
            total_files = 0
            for root, dirs, files in os.walk(self.folder_path.get()):
                # 过滤掉要排除的目录
                dirs[:] = [d for d in dirs if d not in exclude_directories]
                total_files += len(files)
            
            processed_files = 0
            
            # 生成文件树
            self.markdown_content += "## 文件树结构\n\n```\n"
            for root, dirs, files in os.walk(self.folder_path.get()):
                # 过滤掉要排除的目录
                dirs[:] = [d for d in dirs if d not in exclude_directories]
                
                level = root.replace(self.folder_path.get(), '').count(os.sep)
                indent = '  ' * level
                base_dir = os.path.basename(root)
                
                # 只显示非排除的目录
                if base_dir not in exclude_directories:
                    self.markdown_content += f"{indent}└─ {base_dir}/\n"
                    
                    # 显示非排除的文件
                    for file in sorted(files):
                        if not any(file.endswith(ext) for ext in exclude_extensions):
                            self.markdown_content += f"{indent}  └─ {file}\n"
                        
                        processed_files += 1
                        progress = (processed_files / total_files) * 100
                        self.update_progress(progress, f"处理中... {processed_files}/{total_files}")
            
            self.markdown_content += "```\n\n"
            
            # 生成文件内容
            self.markdown_content += "## 文件内容\n\n"
            processed_files = 0
            
            for root, dirs, files in os.walk(self.folder_path.get()):
                # 过滤掉要排除的目录
                dirs[:] = [d for d in dirs if d not in exclude_directories]
                
                if os.path.basename(root) in exclude_directories:
                    continue
                    
                for file in sorted(files):
                    if not any(file.endswith(ext) for ext in exclude_extensions):
                        file_path = os.path.join(root, file)
                        try:
                            with open(file_path, 'r', encoding='utf-8') as f:
                                content = f.read()
                                self.markdown_content += f"### {os.path.relpath(file_path, self.folder_path.get())}\n\n"
                                self.markdown_content += f"```\n{content}\n```\n\n"
                        except Exception as e:
                            self.markdown_content += f"### {os.path.relpath(file_path, self.folder_path.get())}\n\n"
                            self.markdown_content += f"无法读取文件内容: {str(e)}\n\n"
                    
                    processed_files += 1
                    progress = (processed_files / total_files) * 100
                    self.update_progress(progress, f"处理中... {processed_files}/{total_files}")
            
            self.update_preview()
            self.update_progress(100, "分析完成")
            
        except Exception as e:
            self.update_status(f"错误: {str(e)}")
        finally:
            self.is_processing = False
            self.enable_buttons()
    
    def update_progress(self, value, status):
        self.progress['value'] = value
        self.update_status(status)
    
    def update_status(self, status):
        self.status_label.config(text=status)
    
    def update_preview(self):
        self.preview_text.delete(1.0, tk.END)
        self.preview_text.insert(1.0, self.markdown_content)
    
    def enable_buttons(self):
        self.analyze_button.config(state='normal')
        self.save_button.config(state='normal')
    
    def save_markdown(self):
        file_path = filedialog.asksaveasfilename(
            defaultextension=".md",
            filetypes=[("Markdown files", "*.md"), ("All files", "*.*")]
        )
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(self.markdown_content)
                messagebox.showinfo("成功", "Markdown文件保存成功")
            except Exception as e:
                messagebox.showerror("错误", f"保存文件时发生错误: {str(e)}")

if __name__ == "__main__":
    app = FileTreeAnalyzer()
    app.mainloop()